package com.xuyiwei.xblog.modular.system.controller;

import com.baomidou.mybatisplus.plugins.Page;
import com.xuyiwei.xblog.business.system.result.user.input.UserConditionVO;
import com.xuyiwei.xblog.business.system.result.user.input.UserParam;
import com.xuyiwei.xblog.business.system.result.user.out.UserDto;
import com.xuyiwei.xblog.core.base.constant.enums.UserStatusEnum;
import com.xuyiwei.xblog.core.base.controller.BaseController;
import com.xuyiwei.xblog.core.base.response.Result;
import com.xuyiwei.xblog.core.common.annotion.BussinessLog;
import com.xuyiwei.xblog.core.common.annotion.Permission;
import com.xuyiwei.xblog.core.common.constant.Const;
import com.xuyiwei.xblog.core.common.constant.dictmap.UserDict;
import com.xuyiwei.xblog.core.common.constant.factory.ConstantFactory;
import com.xuyiwei.xblog.core.common.constant.factory.PageFactory;
import com.xuyiwei.xblog.core.config.properties.GunsProperties;
import com.xuyiwei.xblog.core.datascope.DataScope;
import com.xuyiwei.xblog.core.exception.BizExceptionEnum;
import com.xuyiwei.xblog.core.exception.GunsException;
import com.xuyiwei.xblog.core.log.LogObjectHolder;
import com.xuyiwei.xblog.core.page.PageInfoBT;
import com.xuyiwei.xblog.core.shiro.ShiroKit;
import com.xuyiwei.xblog.core.shiro.ShiroUser;
import com.xuyiwei.xblog.core.support.StrKit;
import com.xuyiwei.xblog.core.util.OssUtil;
import com.xuyiwei.xblog.core.util.ToolUtil;
import com.xuyiwei.xblog.modular.system.factory.UserFactory;
import com.xuyiwei.xblog.business.system.model.User;
import com.xuyiwei.xblog.business.system.service.IUserService;
import com.xuyiwei.xblog.modular.system.warpper.UserWarpper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.naming.NoPermissionException;
import javax.validation.Valid;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 系统管理员控制器
 *
 * @author fengshuonan
 * @Date 2017年1月11日 下午1:08:17
 */
@Controller
@RequestMapping("/mgr")
public class UserMgrController extends BaseController {

    private static String PREFIX = "/system/user/";

    @Autowired
    private GunsProperties gunsProperties;

    @Autowired
    private IUserService userService;

    /**
     * 跳转到查看管理员列表的页面
     */
    @RequestMapping("")
    public String index() {
        return PREFIX + "user.html";
    }

    /**
     * 跳转到查看管理员列表的页面
     */
    @RequestMapping("/user_add")
    public String addView() {
        return PREFIX + "user_add.html";
    }

    /**
     * 跳转到角色分配页面
     */
    //@RequiresPermissions("/mgr/role_assign")  //利用shiro自带的权限检查
    @Permission
    @RequestMapping("/role_assign")
    public String roleAssign(@RequestParam(required = true, value = "ids[]") List<Integer> ids, Model model) {
        if (ToolUtil.isEmpty(ids)) {
            throw new GunsException(BizExceptionEnum.REQUEST_NULL);
        }
//        User user = userService.selectUsers();
//        UserConditionVo userParam = new UserConditionVo();
//        userParam.setIds(ids.toArray(new Integer[0]));
//        List<Map<String, Object>>  users = userService.selectUsers(userParam);
        model.addAttribute("ids", ids);

//        model.addAttribute("userAccount","11111");
        return PREFIX + "user_roleassign.html";
    }

    /**
     * 跳转到编辑管理员页面
     */
    @Permission
    @RequestMapping("/user_edit/{userId}")
    public String userEdit(@PathVariable Long userId, Model model) {
        if (ToolUtil.isEmpty(userId)) {
            throw new GunsException(BizExceptionEnum.REQUEST_NULL);
        }
        assertAuth(userId);
        User user = this.userService.selectById(userId);
        UserDto userDto = new UserDto();
        BeanUtils.copyProperties(user,userDto);
        String avatar =  user.getAvatar();
        userDto.setAvatarImg(OssUtil.getUrl(avatar));
        model.addAttribute("user",userDto);
        model.addAttribute("roleName", ConstantFactory.me().getRoleName(user.getRoleid()));
        model.addAttribute("deptName", ConstantFactory.me().getDeptName(user.getDeptid()));

        LogObjectHolder.me().set(user);
        return PREFIX + "user_edit.html";
    }

    /**
     * 跳转到查看用户详情页面
     */
    @RequestMapping("/user_info")
    public String userInfo(Model model) {
        Long userId = ShiroKit.getUser().getId();
        if (ToolUtil.isEmpty(userId)) {
            throw new GunsException(BizExceptionEnum.REQUEST_NULL);
        }
        User user = this.userService.selectById(userId);
        UserDto userDto = new UserDto();
        BeanUtils.copyProperties(user,userDto);
        userDto.setAvatarImg(OssUtil.getUrl(user.getAvatar()));
        model.addAttribute("user",userDto);
        model.addAttribute("roleName", ConstantFactory.me().getRoleName(user.getRoleid()));
        model.addAttribute("deptName", ConstantFactory.me().getDeptName(user.getDeptid()));
        LogObjectHolder.me().set(user);
        return PREFIX + "user_view.html";
    }

    /**
     * 跳转到修改密码界面
     */
    @RequestMapping("/user_chpwd")
    public String chPwd() {
        return PREFIX + "user_chpwd.html";
    }

    /**
     * 修改当前用户的密码
     */
    @RequestMapping("/changePwd")
    @ResponseBody
    public Object changePwd(@RequestParam String oldPwd, @RequestParam String newPwd, @RequestParam String rePwd) {
        Result<Boolean> result = Result.instance();
        try{
            if (!newPwd.equals(rePwd)) {
                throw new GunsException(BizExceptionEnum.TWO_PWD_NOT_MATCH);
            }
            Long userId = ShiroKit.getUser().getId();
            User user = userService.selectById(userId);
            String oldMd5 = ShiroKit.md5(oldPwd, user.getSalt());
            if (user.getPassword().equals(oldMd5)) {
                String newMd5 = ShiroKit.md5(newPwd, user.getSalt());
                user.setPassword(newMd5);
                user.updateById();
            } else {
                throw new GunsException(BizExceptionEnum.OLD_PWD_NOT_RIGHT);
            }
            result.setData(true);
        }catch (GunsException e){
            result.setError(e);
        }catch (Exception e){
            result.setError(BizExceptionEnum.TWO_PWD_NOT_MATCH);
        }
        return result;
    }

    /**
     * 查询管理员列表
     */
    @RequestMapping("/list")
    @Permission
    @ResponseBody
    public Result<PageInfoBT<UserDto>> list(UserConditionVO vo) {
        Result<PageInfoBT<UserDto>> result = Result.instance();
        try {
            Page<UserDto> page = new PageFactory<UserDto>().defaultPage();

            if (ShiroKit.isAdmin()) {
                List<UserDto> users = userService.findPageByCondition(page,vo, page.getOrderByField(), page.isAsc());
                page.setRecords((List<UserDto>)new UserWarpper(users).warp());
                result.setData(super.packForBT(page));
            } else {
                DataScope dataScope = new DataScope(ShiroKit.getDeptDataScope());
                vo.setDataScope(dataScope);
                List<UserDto> users = userService.findPageByCondition(page,vo, page.getOrderByField(), page.isAsc());
                page.setRecords((List<UserDto>)new UserWarpper(users).warp());
                result.setData(super.packForBT(page));
            }
        }catch (Exception e){
            result.setError("500","查询管理员列表出错");
        }
        return result;
    }

    /**
     * 添加管理员
     */
    @RequestMapping("/add")
    @BussinessLog(value = "添加管理员", key = "account", dict = UserDict.class)
    @Permission(Const.ADMIN_NAME)
    @ResponseBody
    public Result<Boolean> add(@Valid UserParam user, BindingResult bindingResult) {
        Result<Boolean> result = Result.instance();
        try{
            if (bindingResult.hasErrors()) {
                throw new GunsException(BizExceptionEnum.REQUEST_NULL);
            }

            // 判断账号是否重复
            User theUser = userService.getByAccount(user.getAccount());
            if (theUser != null) {
                throw new GunsException(BizExceptionEnum.USER_ALREADY_REG);
            }

            // 完善账号信息
            user.setSalt(ShiroKit.getRandomSalt(5));
            user.setPassword(ShiroKit.md5(user.getPassword(), user.getSalt()));
            user.setStatus(UserStatusEnum.USE.getKey());
            user.setCreateTime(new Date());

            this.userService.insert(UserFactory.createUser(user));
            result.setData(true);
        }catch (GunsException e){
            result.setError(e);
        }catch (Exception e){
            result.setError(BizExceptionEnum.REQUEST_NULL);
        }
        return result;
    }

    /**
     * 修改管理员
     *
     * @throws NoPermissionException
     */
    @RequestMapping("/edit")
    @BussinessLog(value = "修改管理员", key = "account", dict = UserDict.class)
    @ResponseBody
    public Result<Boolean> edit(@Valid UserParam user, BindingResult bindingResult) throws NoPermissionException {
        Result<Boolean> result = Result.instance();
        try{
            if (bindingResult.hasErrors()) {
                throw new GunsException(BizExceptionEnum.REQUEST_NULL);
            }

            User oldUser = userService.selectById(user.getId());

            if (ShiroKit.hasRole(Const.ADMIN_NAME)) {
                this.userService.updateById(UserFactory.editUser(user, oldUser));
            } else {
                assertAuth(user.getId());
                ShiroUser shiroUser = ShiroKit.getUser();
                if (shiroUser.getId().equals(user.getId())) {
                    this.userService.updateById(UserFactory.editUser(user, oldUser));
                } else {
                    throw new GunsException(BizExceptionEnum.NO_PERMITION);
                }
            }
            result.setData(true);
        }catch (GunsException e){
            result.setError(e);
        }catch (Exception e){
            result.setError(BizExceptionEnum.REQUEST_NULL);
        }
        return result;
    }

    /**
     * 删除管理员（逻辑删除）
     */
    @RequestMapping("/delete")
    @BussinessLog(value = "删除管理员", key = "ids", dict = UserDict.class)
    @Permission
    @ResponseBody
    @Transactional
    public Result<Boolean> delete(@RequestParam(required = true, value = "ids[]") List<Long> ids) {
        Result<Boolean> result = Result.instance();
        try{
            if (ToolUtil.isEmpty(ids)) {
                throw new GunsException(BizExceptionEnum.REQUEST_NULL);
            }
            //不能删除超级管理员
            for(Long id : ids){
                if (id.equals(Const.ADMIN_ID)) {
                    throw new GunsException(BizExceptionEnum.CANT_DELETE_ADMIN);
                }
                //看看删除的用户在不在自己的数据范围之内
                assertAuth(id);
            }
            Long[] idsInteger = ids.toArray(new Long[0]);
            this.userService.setStatusIds(idsInteger, UserStatusEnum.DELETE.getKey());
            result.setData(true);
        }catch (GunsException e){
            result.setError(e);
        }catch (Exception e){
            result.setError(BizExceptionEnum.REQUEST_NULL);
        }
        return result;
    }

    /**
     * 查看管理员详情
     */
    @RequestMapping("/view/{userId}")
    @ResponseBody
    public Result<User> view(@PathVariable Long userId) {
        Result<User> result = Result.instance();
        try{
            if (ToolUtil.isEmpty(userId)) {
                throw new GunsException(BizExceptionEnum.REQUEST_NULL);
            }
            assertAuth(userId);
            result.setData(this.userService.selectById(userId));
        }catch (Exception e){
            result.setError("500","查看管理员详情失败");
        }
        return result;
    }

    /**
     * 重置管理员的密码
     */
    @RequestMapping("/reset")
    @BussinessLog(value = "重置管理员密码", key = "ids", dict = UserDict.class)
    @Permission(Const.ADMIN_NAME)
    @ResponseBody
    public Result<Boolean> reset(@RequestParam(required = true, value = "ids[]") List<Long> ids) {
        Result<Boolean> result = Result.instance();
        try {
            if (ToolUtil.isEmpty(ids)) {
                throw new GunsException(BizExceptionEnum.REQUEST_NULL);
            }
            for(Long id:ids){
                assertAuth(id);
                User user = this.userService.selectById(id);
                user.setSalt(ShiroKit.getRandomSalt(5));
                user.setPassword(ShiroKit.md5(Const.DEFAULT_PWD, user.getSalt()));
                this.userService.updateById(user);
            }
            result.setData(true);
        }catch (Exception e){
            result.setError(BizExceptionEnum.REQUEST_NULL);
        }
        return result;
    }

    /**
     * 冻结用户
     */
    @RequestMapping("/freeze")
    @BussinessLog(value = "冻结用户", key = "ids", dict = UserDict.class)
    @Permission(Const.ADMIN_NAME)
    @ResponseBody
    public Result<Boolean> freeze(@RequestParam(required = true, value = "ids[]") List<Long> ids) {
        Result<Boolean> result = Result.instance();
        try{
            if (ToolUtil.isEmpty(ids)) {
                throw new GunsException(BizExceptionEnum.REQUEST_NULL);
            }
            //不能冻结超级管理员
            for(Long id:ids){
                if (id.equals(Const.ADMIN_ID)) {
                    throw new GunsException(BizExceptionEnum.CANT_FREEZE_ADMIN);
                }
                assertAuth(id);
            }
            this.userService.setStatusIds(ids.toArray(new Long[0]), UserStatusEnum.FREEZED.getKey());
            result.setData(true);
        }catch (GunsException e){
            result.setError(e);
        }catch (Exception e){
            result.setError(BizExceptionEnum.REQUEST_NULL);
        }
        return result;
    }

    /**
     * 解除冻结用户
     */
    @RequestMapping("/unfreeze")
    @BussinessLog(value = "解除冻结用户", key = "userId", dict = UserDict.class)
    @Permission(Const.ADMIN_NAME)
    @ResponseBody
    public Result<Boolean> unfreeze(@RequestParam(required = true, value = "ids[]") List<Long> ids) {
        Result<Boolean> result = Result.instance();
        try{
            if (ToolUtil.isEmpty(ids)) {
                throw new GunsException(BizExceptionEnum.REQUEST_NULL);
            }
            //不能冻结超级管理员
            for(Long id:ids){
                if (id.equals(Const.ADMIN_ID)) {
                    throw new GunsException(BizExceptionEnum.CANT_FREEZE_ADMIN);
                }
                assertAuth(id);
            }
            this.userService.setStatusIds(ids.toArray(new Long[0]), UserStatusEnum.USE.getKey());
            result.setData(true);
        }catch (GunsException e){
            result.setError(e);
        }catch (Exception e){
            result.setError(BizExceptionEnum.REQUEST_NULL);
        }
        return result;
    }

    /**
     * 分配角色
     */
    @RequestMapping("/setRole")
    @BussinessLog(value = "分配角色", key = "ids,roleIds", dict = UserDict.class)
    @Permission(Const.ADMIN_NAME)
    @ResponseBody
    public Result<Boolean> setRole(@RequestParam(required = true, value = "ids[]") List<Long> ids, @RequestParam("roleIds") String roleIds) {
        Result<Boolean> result = Result.instance();
        try{
            if (ToolUtil.isOneEmpty(ids, roleIds)) {
                throw new GunsException(BizExceptionEnum.REQUEST_NULL);
            }
            //不能修改超级管理员
            for(Long id:ids) {
                if (id.equals(Const.ADMIN_ID)) {
                    throw new GunsException(BizExceptionEnum.CANT_CHANGE_ADMIN);
                }
                assertAuth(id);
                this.userService.setRoles(id, roleIds);
            }
            result.setData(true);
        }catch (GunsException e){
            result.setError(e);
        }catch (Exception e){
            result.setError(BizExceptionEnum.REQUEST_NULL);
        }
        return result;
    }

    /**
     * 判断当前登录的用户是否有操作这个用户的权限
     */
    private void assertAuth(Long userId) {
        if (ShiroKit.isAdmin()) {
            return;
        }
        List<Long> deptDataScope = ShiroKit.getDeptDataScope();
        User user = this.userService.selectById(userId);
        Long deptid = user.getDeptid();
        if (deptDataScope.contains(deptid)) {
            return;
        } else {
            throw new GunsException(BizExceptionEnum.NO_PERMITION);
        }

    }
}
